#ifndef _AUDIO_MANAGER_H_
#define _AUDIO_MANAGER_H_

// AUDIO MANAGER by ADRIAN TUNG
//
// HOW TO USE
// ----------
// 1) Create new class for AudioData
// 2) Initialize AudioManager with AUDIOMAN().Load( --your data class here-- )
// 3) Register AudioManager's Lua functions
// 4) Call AUDIOMAN().Tick() in application's Tick cycle
//


#include "audio/audio.h"


namespace LuaPlus
{
    class LuaState;
};

namespace audio
{

class AudioData
{
public:
							AudioData() {}
	virtual					~AudioData() {}

// defaults
	virtual unsigned int	GetMainThemeID() const		{ return 0; }
	virtual std::string		GetBasePath() const			{ return "sounds/"; }
	virtual std::string		GetSoundBank() const		{ return "soundbank.lua"; }
	virtual std::string		GetSoundExt() const			{ return ".ogg"; }
	virtual bool			MusicRepeats(int ID) const	{ return false; }

// must override these
	virtual int				GetMusicC() const = 0;
	virtual int				GetStingC() const = 0;
	virtual int				GetAudioEventC() const = 0;
	virtual int				GetLoopEventC() const = 0;

	virtual std::string		MapMusicToString(unsigned int ID) = 0;
	virtual std::string		MapStingToString(unsigned int ID) = 0;
	virtual std::string		MapAudioToString(unsigned int ID) = 0;
	virtual std::string		MapLoopToString(unsigned int ID) = 0;

// events
	virtual void			OnMusicRepeat(int& CurMusic) {}
	virtual void			OnStingComplete(int& CurMusic) {}

// default mapping
	virtual unsigned int	MapStringToMusic(const std::string& name)
	{
		for (int i = 0; i < GetMusicC(); i++) {
			
			if (stricmp(name.c_str(), MapMusicToString(i).c_str()) == 0)
				return i;
		}
		return 0;
	}
	virtual unsigned int	MapStringToSting(const std::string& name)
	{
		for (int i = 0; i < GetStingC(); i++) {
			if (stricmp(name.c_str(), MapStingToString(i).c_str()) == 0)
				return i;
		}
		return 0;
	}
	virtual unsigned int	MapStringToAudio(const std::string& name)
	{
		for (int i = 0; i < GetAudioEventC(); i++) {
			if (stricmp(name.c_str(), MapAudioToString(i).c_str()) == 0)
				return i;
		}
		return 0;
	}
	virtual unsigned int	MapStringToLoop(const std::string& name)
	{
		for (int i = 0; i < GetLoopEventC(); i++) {
			if (stricmp(name.c_str(), MapLoopToString(i).c_str()) == 0)
				return i;
		}
		return 0;
	}
};

class AudioManager
{
public:
	AudioManager();
	virtual ~AudioManager();

	static AudioManager&	Instance();

	void					Load(AudioData* pData, bool DeleteData = true);
	void					Tick(float dt);
	bool					IsPlaying();

// music and stings
	void					SetTheme(unsigned int ID, bool PlayNow = true);
	void					PlaySting(unsigned int ID);
	void					ResumeCurrent();

// sound fx
	void					PlaySoundEvent(unsigned int ID, bool TriggerNow = false);
	void					PlayLoop(unsigned int ID);
	void					StopLoop(unsigned int ID, bool StopAll = false);

// luabind
	static void				Register(LuaPlus::LuaState* _pScript);
	void					SetThemeStr(const std::string& name, bool PlayNow);
	void					PlayStingStr(const std::string& name);
	void					PlaySoundStr(const std::string& name, bool TriggerNow);
	void					PlayLoopStr(const std::string& name);
	void					StopLoopStr(const std::string& name, bool StopAll);

private:
	void					TriggerSounds();
	inline std::string		Cat(const std::string& s);

	AudioData*				m_pData;
	audio::AudioFile*		m_pThemes;
	audio::AudioFile*		m_pStings;
	audio::AudioHandle		m_Current;
	int						m_CurTheme;
	int						m_ThemePlayC;
	bool					m_IsPlayingSting;

	struct LOOP_DATA {
		audio::AudioHandle	Handle;
		int					Count;
	};
	LOOP_DATA*				m_pLoops;
	int*					m_pEvents;

	bool					m_bDeleteData;
};

} //namespace audio

#define AUDIOMAN()			audio::AudioManager::Instance()

#endif // _AUDIO_MANAGER_H_
